/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "Model.h"
#include <xml/Stream.h>
#include <logs/Log.h>
#include <Gluck.h>
//#include <Rnd.h>
#include <math/Miniball.h>
#include <Endianess.h>

namespace liba
{
namespace lib3d
{
namespace model
{

const Atom Model::position_name("Positions");
const Atom Model::normal_name("Normals");
const Atom Model::face_normal_name("FaceNormals");
const Atom Model::u_tangent_name("U-Tangents");
const Atom Model::v_tangent_name("V-Tangents");
const Atom Model::diffuse_name("Diffuses");
const Atom Model::specular_name("Speculars");
const Atom Model::uv0_name("UV0");
const Atom Model::uv1_name("UV1");
const Atom Model::uv2_name("UV2");
const Atom Model::uv3_name("UV3");
const Atom Model::weights0_name("Weights0");
const Atom Model::weights1_name("Weights1");
const Atom Model::weights2_name("Weights2");
const Atom Model::indices0_name("Indices0");
const Atom Model::indices1_name("Indices1");
const Atom Model::indices2_name("Indices2");
const Atom Model::indices3_name("Indices3");
const Atom Model::index_name("Indices");

Model::Model(const filesystem::String & name)
:	res( new resource::ActiveMultithreaded(name) ),
	name( name )
{
	start_loading();
}

Model::~Model()
{}

void Model::load(const filesystem::String & name)
{
	if( !res )
		return;
	if( !res->is_ready() )
		return;

	res->reset();

	int count = 0;

	// positions
	res->read(&count, sizeof(int));

	SimpleArray<float> positions(count);
	res->read(positions.data(), count * sizeof(float));

	// normals
	res->read(&count, sizeof(int));

	SimpleArray<float> normals(count);
	res->read(normals.data(), count * sizeof(float));

	// uvs
	res->read(&count, sizeof(int));

	SimpleArray<float> uvs(count);
	res->read(uvs.data(), count * sizeof(float));

	// colors
	res->read(&count, sizeof(int));

	SimpleArray<float> colors(count);
	res->read(colors.data(), count * sizeof(float));

	// indices
	res->read(&count, sizeof(int));

	SimpleArray<int> indices(count);
	res->read(indices.data(), count * sizeof(int));

	// add values
	add_value(position_name, positions);
	add_value(normal_name, normals);
	add_value(uv0_name, uvs);
	add_value(diffuse_name, colors);
	add_value(index_name, indices);

	//
	math::Miniball<3> mb;
	for( size_t i = 0; i < positions.size()/3; ++i )
	{
		math::Miniball<3>::Point p;
		p[0] = positions[i*3];
		p[1] = positions[i*3+1];
		p[2] = positions[i*3+2];
		mb.check_in( p );
	}

	mb.build();
	
	Vector center( mb.center()[0], mb.center()[1], mb.center()[2] );
	float radius_square = mb.squared_radius();

	bounding_sphere = Sphere( center, sqrt( radius_square ) );

	res.reset();
	stop_loading();
}

const SimpleArray<float> * Model::find_value_float(const Atom & value_name)const
{
	Floats::const_iterator cit = floats.find( value_name );
	if( cit == floats.end() )
		return &dumb_floats;
	return &cit->second;
}

const SimpleArray<int> * Model::find_value_int(const Atom & value_name)const
{
	Ints::const_iterator cit = ints.find( value_name );
	if( cit == ints.end() )
		return &dumb_ints;
	return &cit->second;
}

void Model::add_value( const Atom & value_name, const SimpleArray<float> & value )
{
	floats[value_name] = value;
}

void Model::add_value( const Atom & value_name, const SimpleArray<int> & value )
{
	ints[value_name] = value;
}

void Model::unload_model()
{
	Floats::iterator it = floats.begin();
	for(; it != floats.end(); ++it)
	{
		it->second.clear();
	}

	Ints::iterator it2 = ints.begin();
	for(; it2 != ints.end(); ++it2)
	{
		it2->second.clear();
	}

	floats.clear();
	ints.clear();
}


} // namespace model
} // namespace lib3d
} // namespace liba

